package com.gogant.spider.core;

import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public abstract class Response {
    private URL url;
    private Map<Key, List<String>> headerFields;
    private String contentEncoding;
    private int contentLength;
    private String contentType;
    private Object content;

    public Response(Request req, URLConnection conn) {
        url = conn.getURL();
        setHeaders(conn.getHeaderFields());
        contentEncoding = conn.getContentEncoding();
        contentLength = conn.getContentLength();
        contentType = conn.getContentType();
    }

    /**
     * 获取URL
     *
     * @return
     */
    public final URL getURL() {
        return url;
    }

    /**
     * 获取所有响应头部信息
     *
     * @return
     */
    public final Map<String, List<String>> getHeaderMap() {
        if (headerFields == null) {
            return null;
        }
        Map<String, List<String>> fields = new HashMap<String, List<String>>();
        for (Entry<Key, List<String>> entry : headerFields.entrySet()) {
            fields.put(entry.getKey().name, entry.getValue());
        }
        return fields;
    }

    private void setHeaders(Map<String, List<String>> headerFields) {
        if (headerFields == null) {
            this.headerFields = null;
        }
        Map<Key, List<String>> fields = new HashMap<Key, List<String>>();
        for (Entry<String, List<String>> entry : headerFields.entrySet()) {
            if (entry.getKey() == null) {
                continue;
            }
            fields.put(new Key(entry.getKey()), entry.getValue());
        }
        this.headerFields = fields;
    }

    /**
     * 获取响应头属性
     *
     * @param name
     * @return
     */
    public final String getHeader(String name) {
        return getHeader(name, null);
    }

    /**
     * 获取响应头属性，如果不存在，则返回默认值
     *
     * @param name
     * @param deft
     * @return
     */
    public final String getHeader(String name, String deft) {
        if (headerFields == null) {
            return null;
        }
        List<String> values = headerFields.get(new Key(name));
        if (values == null || values.size() == 0) {
            return deft;
        } else {
            return values.get(0);
        }
    }

    /**
     * 设置内容编码
     *
     * @param contentEncoding
     */
    public final void setContentEncoding(String contentEncoding) {
        this.contentEncoding = contentEncoding;
    }

    /**
     * 获取内容编码
     *
     * @return
     */
    public final String getContentEncoding() {
        return contentEncoding;
    }

    /**
     * 获取内容长度
     *
     * @return
     */
    public final int getContentLength() {
        return contentLength;
    }

    /**
     * 设置内容长度
     *
     * @param contentLength
     */
    public final void setContentLength(int contentLength) {
        this.contentLength = contentLength;
    }

    /**
     * 获取内容类型
     *
     * @return
     */
    public final String getContentType() {
        return contentType;
    }

    /**
     * 设置内容类型
     *
     * @param contentType
     */
    public final void setContentType(String contentType) {
        this.contentType = contentType;
    }

    /**
     * 获取响应内容
     *
     * @return
     */
    public final Object getContent() {
        return content;
    }

    /**
     * 根据指定类型获取响应内容，如果内容为空或者指定的类型不符都返回null，否则返回指定的类型数据
     *
     * @param clazz
     * @param <T>
     * @return
     */
    @SuppressWarnings("unchecked")
    public final <T> T getContent(Class<T> clazz) {
        if (content == null || !clazz.isInstance(content)) {
            return null;
        }
        return (T) content;
    }

    /**
     * 设置响应内容
     *
     * @param content
     */
    public final void setContent(Object content) {
        this.content = content;
    }

    private class Key {
        String name;
        String key;

        public Key(String name) {
            this.name = name;
            this.key = name.toLowerCase();
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + getOuterType().hashCode();
            result = prime * result + ((key == null) ? 0 : key.hashCode());
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Key other = (Key) obj;
            if (!getOuterType().equals(other.getOuterType()))
                return false;
            if (key == null) {
                if (other.key != null)
                    return false;
            } else if (!key.equals(other.key))
                return false;
            return true;
        }

        private Response getOuterType() {
            return Response.this;
        }

        @Override
        public String toString() {
            return name;
        }
    }
}
